package com.cardone.platform.authority.service;

import com.cardone.common.service.SimpleDefaultService;
import com.cardone.context.*;
import com.cardone.platform.authority.dao.NavigationDao;
import com.cardone.platform.authority.dto.NavigationDto;
import com.cardone.platform.authority.po.Navigation;
import com.cardone.platform.configuration.service.DictionaryService;
import com.cardone.platform.configuration.service.SiteService;
import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;

/**
 * 导航服务
 *
 * @author yaohaitao
 */
@Getter
@Setter
@Transactional(readOnly = true)
public class NavigationDefaultService extends SimpleDefaultService<NavigationDto> implements NavigationService {
    @Override
    @Transactional
    public <P> P saveByIdOrCode(final Class<P> mappedClass, final NavigationDto saveNavigation, String... selectNames) {
        if (StringUtils.isBlank(saveNavigation.getSiteId())) {
            throw new DictionaryException("站点标识不能为空值").setTypeCode("navigation").setCode("isBlankSiteId");
        }

        if (StringUtils.isBlank(saveNavigation.getTypeId())) {
            throw new DictionaryException("类别标识不能为空值").setTypeCode("navigation").setCode("isBlankTypeId");
        }

        if (StringUtils.isBlank(saveNavigation.getCode())) {
            throw new DictionaryException("编号不能为空值").setTypeCode("navigation").setCode("isBlankCode");
        }

        if (StringUtils.isBlank(saveNavigation.getName())) {
            throw new DictionaryException("名称不能为空值").setTypeCode("navigation").setCode("isBlankName");
        }

        final int oldCount = this.readByCodeNqIdForCount(saveNavigation);

        if (oldCount > 0) {
            throw new DictionaryException("编号有冲突").setTypeCode("navigation").setCode("oldData");
        }

        return ContextHolder.getBean(NavigationDao.class).saveByIdOrCode(mappedClass, saveNavigation, selectNames);
    }

    @Override
    public NavigationDao getDao() {
        return ContextHolder.getBean(NavigationDao.class);
    }

    @Override
    @Transactional
    public int insertByCode(final NavigationDto insertNavigation) {
        if (StringUtils.isBlank(insertNavigation.getSiteId())) {
            throw new DictionaryException("站点标识不能为空值").setTypeCode("navigation").setCode("isBlankSiteId");
        }

        if (StringUtils.isBlank(insertNavigation.getTypeId())) {
            throw new DictionaryException("类别标识不能为空值").setTypeCode("navigation").setCode("isBlankTypeId");
        }

        if (StringUtils.isBlank(insertNavigation.getCode())) {
            throw new DictionaryException("编号不能为空值").setTypeCode("navigation").setCode("isBlankCode");
        }

        if (StringUtils.isBlank(insertNavigation.getName())) {
            throw new DictionaryException("名称不能为空值").setTypeCode("navigation").setCode("isBlankName");
        }

        final int oldCount = this.readByCodeNqIdForCount(insertNavigation);

        if (oldCount > 0) {
            throw new DictionaryException("编号有冲突").setTypeCode("navigation").setCode("oldData");
        }

        return ContextHolder.getBean(NavigationDao.class).insertByCode(insertNavigation);
    }

    @Override
    @Transactional(readOnly = true)
    public List<NavigationDto> findListByParentIdForTree(final String siteCode, final String typeCode, final String parentId, final int level) {
        final String newTypeCode = StringUtils.defaultString(typeCode, Contexts.main.name());

        final List<NavigationDto> navigationList = ContextHolder.getBean(NavigationService.class).findListBySiteCodeAndTypeCode(siteCode, newTypeCode);

        return buildByParentIdForTree(navigationList, parentId, level);
    }

    @Override
    @Transactional(readOnly = true)
    public List<NavigationDto> findListByParentId(final String siteCode, final String typeCode, final String parentId) {
        return ContextHolder.getBean(NavigationDao.class).findListByParentId(NavigationDto.class, siteCode, typeCode, parentId);
    }

    @Override
    public java.util.List<com.cardone.platform.authority.dto.NavigationDto> findListBySiteCodeAndTypeCode(String siteCode, String typeCode) {
        return ContextHolder.getBean(NavigationDao.class).findListBySiteCodeAndTypeCode(NavigationDto.class, siteCode, typeCode);
    }

    @Override
    @Transactional(readOnly = true)
    public List<NavigationDto> findListByParentCode(final String siteCode, final String typeCode, final String parentCode) {
        return ContextHolder.getBean(NavigationDao.class).findListByParentCode(NavigationDto.class, siteCode, typeCode, parentCode);
    }

    @Override
    @Transactional(readOnly = true)
    public List<NavigationDto> findListByParentCodeForTree(final String siteCode, final String typeCode, final String parentCode, final int level) {
        final String newTypeCode = StringUtils.defaultString(typeCode, Contexts.main.name());

        final List<NavigationDto> navigationList = ContextHolder.getBean(NavigationService.class).findListBySiteCodeAndTypeCode(siteCode, newTypeCode);

        return buildByParentCodeForTree(navigationList, parentCode, level);
    }

    @Override
    @CacheEvict(value = NavigationService.BEAN_ID, allEntries = true)
    public void init() {
        this.init(Navigation.class.getName() + ".initList");
    }

    @Transactional
    public void init(final List<NavigationDto> initNavigationList) {
        if (CollectionUtils.isEmpty(initNavigationList)) {
            return;
        }

        for (final NavigationDto initNavigation : initNavigationList) {
            if (StringUtils.isBlank(initNavigation.getSiteId())) {
                Map<String, Object> findSiteMap = Maps.newHashMap();

                findSiteMap.put(Attributes.code.name(), initNavigation.getSiteCode());

                final String siteId = ContextHolder.getBean(SiteService.class).readByCode(String.class, Attributes.id.name(), findSiteMap);

                if (StringUtils.isBlank(siteId)) {
                    continue;
                }

                initNavigation.setSiteId(siteId);
            }

            if (StringUtils.isBlank(initNavigation.getTypeId())) {
                final String typeId = ContextHolder.getBean(DictionaryService.class).readIdByTypeCodeAndCode(initNavigation.getTypeTypeCode(), initNavigation.getTypeCode());

                if (StringUtils.isBlank(typeId)) {
                    continue;
                }

                initNavigation.setTypeId(typeId);
            }

            final NavigationDto oldNavigation = ContextHolder.getBean(NavigationDao.class).saveByIdOrCode(NavigationDto.class, initNavigation);

            if (CollectionUtils.isEmpty(initNavigation.getChilds())) {
                continue;
            }

            for (final NavigationDto childNavigation : initNavigation.getChilds()) {
                childNavigation.setSiteId(oldNavigation.getSiteId());

                childNavigation.setTypeId(oldNavigation.getTypeId());

                childNavigation.setParentId(oldNavigation.getId());

                childNavigation.setTreeTypeCode(initNavigation.getTreeTypeCode());

                childNavigation.setTreeCode(initNavigation.getTreeCode());
            }

            this.init(initNavigation.getChilds());
        }
    }

    private List<NavigationDto> buildByParentIdForTree(List<NavigationDto> navigationList, final String parentId, final int level) {
        List<NavigationDto> navigationChilds = com.google.common.collect.Lists.newArrayList();

        if (level < 1) {
            return navigationChilds;
        }

        if (CollectionUtils.isEmpty(navigationList)) {
            return navigationChilds;
        }

        navigationList.stream().filter(it -> StringUtils.equals(parentId, it.getParentId())).forEach(it -> {
            navigationChilds.add(it);

            if (it.getChildTotal() < 1) {
                return;
            }

            it.setChilds(buildByParentIdForTree(navigationList, it.getId(), (level - 1)));
        });

        return navigationChilds;
    }

    private List<NavigationDto> buildByParentCodeForTree(List<NavigationDto> navigationList, final String parentCode, final int level) {
        List<NavigationDto> navigationChilds = com.google.common.collect.Lists.newArrayList();

        if (level < 1) {
            return navigationChilds;
        }

        if (CollectionUtils.isEmpty(navigationList)) {
            return navigationChilds;
        }

        navigationList.stream().filter(it -> StringUtils.equals(parentCode, it.getParentCode())).forEach(it -> {
                    navigationChilds.add(it);

                    if (it.getChildTotal() < 1) {
                        return;
                    }

                    it.setChilds(buildByParentIdForTree(navigationList, it.getId(), (level - 1)));
                }
        );

        return navigationChilds;
    }
}